package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.ReplyDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.ReplyPageQuery;
import com.tianji.learning.domain.vo.ReplyVO;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.mq.message.SignInMessage;
import com.tianji.learning.service.IInteractionReplyService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.tianji.common.constants.Constant.DATA_FIELD_NAME_CREATE_TIME;
import static com.tianji.common.constants.Constant.DATA_FIELD_NAME_LIKED_TIME;

/**
 * <p>
 * 互动问题的回答或评论 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-04-02
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {
    private final InteractionQuestionMapper interactionQuestionMapper;
    private final UserClient userClient;
    private final RabbitMqHelper mqHelper;

    @Override
    public void addQuestionOrComment(ReplyDTO reply) {
        //1.copy属性
        InteractionReply interactionReply = BeanUtil.copyProperties(reply, InteractionReply.class);
        Long userId = UserContext.getUser();
        interactionReply.setUserId(userId);
        log.info("保存回答数据{}",interactionReply);
        //2.更新数据表
        boolean save = this.save(interactionReply);
        if (!save){
            throw new RuntimeException("保存失败");
        }
        //3.判断是否为回答
        if (reply.getAnswerId() == null && reply.getTargetReplyId() == null ){
            //5.是回答
            handleAnswer(interactionReply);
        }else {
            //4 不是回答，为评论
            handleComment(interactionReply);
        }
        //6.判断是否是学生回答
        if (reply.getIsStudent()){
            //7.将问题表管理端是否查看状态改为false
            handleQuestionStatus(interactionReply,reply);
        }
    }
   /* @Override
    @Transactional
    public void addQuestionOrComment(ReplyDTO replyDTO) {
        // 1.获取登录用户
        Long userId = UserContext.getUser();
        // 2.新增回答
        InteractionReply reply = BeanUtils.toBean(replyDTO, InteractionReply.class);
        reply.setUserId(userId);
        save(reply);
        // 3.累加评论数或者累加回答数
        // 3.1.判断当前回复的类型是否是回答
        boolean isAnswer = replyDTO.getAnswerId() == null;
        if (!isAnswer) {
            // 3.2.是评论，则需要更新上级回答的评论数量
            lambdaUpdate()
                    .setSql("reply_times = reply_times + 1")
                    .eq(InteractionReply::getId, replyDTO.getAnswerId())
                    .update();
        }
        // 3.3.尝试更新问题表中的状态、 最近一次回答、回答数量
        *//*questionService.lambdaUpdate()
                .set(isAnswer, InteractionQuestion::getLatestAnswerId, reply.getAnswerId())
                .setSql(isAnswer, "answer_times = answer_times + 1")
                .set(replyDTO.getIsStudent(), InteractionQuestion::getStatus, QuestionStatus.UN_CHECK.getValue())
                .eq(InteractionQuestion::getId, replyDTO.getQuestionId())
                .update();*//*
        InteractionQuestion question = interactionQuestionMapper.selectById(replyDTO.getQuestionId());

        if (replyDTO.getIsStudent()) {
            question.setStatus(QuestionStatus.of(QuestionStatus.UN_CHECK.getValue()));
        }
        if (isAnswer) {
            question.setAnswerTimes(question.getAnswerTimes() + 1);
            question.setLatestAnswerId(reply.getAnswerId());
        }
        interactionQuestionMapper.updateById(question);

        // 4.尝试累加积分
       *//* if(replyDTO.getIsStudent()) {
            // 学生才需要累加积分
            mqHelper.send(
                    MqConstants.Exchange.LEARNING_EXCHANGE,
                    MqConstants.Key.WRITE_REPLY,
                    5);
        }*//*
    }
*/
   /* @Override
    public PageDTO<ReplyVO> queryReplyPage(ReplyPageQuery query) {
        //1.分页查询回答数据
        Page<InteractionReply> page = this.lambdaQuery()
                .eq(query.getQuestionId() != null,InteractionReply::getQuestionId, query.getQuestionId())
                .eq(query.getAnswerId() != null, InteractionReply::getAnswerId, query.getAnswerId())
                .eq(InteractionReply::getAnonymity, false)
                .page(query.toMpPage("liked_times", false));
        List<InteractionReply> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            log.info("查询结果为空,暂时还没有人回答");
            return PageDTO.empty(page);
        }
        //2.判断是否匿名
        //3.获取用户信息
        //4.封装数据返回结果
        ArrayList<ReplyVO> list = new ArrayList<>();
        for (InteractionReply record : records) {
            ReplyVO vo = BeanUtil.copyProperties(record, ReplyVO.class);
            if (!record.getAnonymity()){
                UserDTO userDTO = userClient.queryUserById(record.getUserId());
                if (userDTO!=null){
                    vo.setUserName(userDTO.getUsername());//回答者姓名
                    vo.setUserIcon(userDTO.getIcon());//回答者头像
                }
            }
            //5.如果目标评论者不是匿名，设置目标评论者姓名
            if (record.getTargetReplyId() != null){
                log.info("分页查询的被回答用户id为{}",record.getAnswerId());
                InteractionReply reply = this.getById(record.getTargetReplyId());
                if (reply!=null && !reply.getAnonymity()){
                    UserDTO userDTO = userClient.queryUserById(reply.getUserId());
                    if (userDTO!=null){
                        vo.setTargetUserName(userDTO.getName());//目标评论者姓名
                    }
                }
            }
            log.info("分页返回对象{}",vo);
            list.add(vo);
        }
        return PageDTO.of(page, list);
    }*/
   @Override
   public PageDTO<ReplyVO> queryReplyPage(ReplyPageQuery query) {
       // 1.问题id和回答id至少要有一个，先做参数判断
       Long questionId = query.getQuestionId();
       Long answerId = query.getAnswerId();
       if (questionId == null && answerId == null) {
           throw new BadRequestException("问题或回答id不能都为空");
       }
       // 标记当前是查询问题下的回答
       boolean isQueryAnswer = questionId != null;
       // 2.分页查询reply
       Page<InteractionReply> page = lambdaQuery()
               .eq(isQueryAnswer, InteractionReply::getQuestionId, questionId)
               .eq(InteractionReply::getAnswerId, isQueryAnswer ? 0L : answerId)
               //.eq(!forAdmin, InteractionReply::getHidden, false)
               .page(query.toMpPage( // 先根据点赞数排序，点赞数相同，再按照创建时间排序
                       new OrderItem(DATA_FIELD_NAME_LIKED_TIME, false),
                       new OrderItem(DATA_FIELD_NAME_CREATE_TIME, true))
               );
       List<InteractionReply> records = page.getRecords();
       if (CollUtils.isEmpty(records)) {
           return PageDTO.empty(page);
       }
       // 3.数据处理，需要查询：提问者信息、回复目标信息、当前用户是否点赞
       Set<Long> userIds = new HashSet<>();
       Set<Long> answerIds = new HashSet<>();
       Set<Long> targetReplyIds = new HashSet<>();
       // 3.1.获取提问者id 、回复的目标id、当前回答或评论id（统计点赞信息）
       for (InteractionReply r : records) {
           if(!r.getAnonymity()/* || forAdmin*/) {
               // 非匿名
               userIds.add(r.getUserId());
           }
           targetReplyIds.add(r.getTargetReplyId());
           answerIds.add(r.getId());
       }
       // 3.2.查询目标回复，如果目标回复不是匿名，则需要查询出目标回复的用户信息
       targetReplyIds.remove(0L);
       targetReplyIds.remove(null);
       if(!targetReplyIds.isEmpty()) {
           List<InteractionReply> targetReplies = listByIds(targetReplyIds);
           Set<Long> targetUserIds = targetReplies.stream()
                   .filter(Predicate.not(InteractionReply::getAnonymity)/*.or(r -> forAdmin)*/)
                   .map(InteractionReply::getUserId)
                   .collect(Collectors.toSet());
           userIds.addAll(targetUserIds);
       }
       // 3.3.查询用户
       Map<Long, UserDTO> userMap = new HashMap<>(userIds.size());
       if(!userIds.isEmpty() ) {
           List<UserDTO> users = userClient.queryUserByIds(userIds);
           userMap = users.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));
       }

       // 4.处理VO
       List<ReplyVO> list = new ArrayList<>(records.size());
       for (InteractionReply r : records) {
           // 4.1.拷贝基础属性
           ReplyVO v = BeanUtils.toBean(r, ReplyVO.class);
           list.add(v);
           // 4.2.回复人信息
           if(!r.getAnonymity() /*|| forAdmin*/){
               UserDTO userDTO = userMap.get(r.getUserId());
               if (userDTO != null) {
                   v.setUserIcon(userDTO.getIcon());
                   v.setUserName(userDTO.getName());
                   v.setUserType(userDTO.getType());
               }
           }
           // 4.3.如果存在评论的目标，则需要设置目标用户信息
           if(r.getTargetReplyId() != null){
               UserDTO targetUser = userMap.get(r.getTargetUserId());
               if (targetUser != null) {
                   v.setTargetUserName(targetUser.getName());
               }
           }
           v.setLikedTimes(r.getLikedTimes());
       }
       return PageDTO.of(page, list);
   }

    @Override
    public PageDTO<ReplyVO> queryAdminReplyPage(ReplyPageQuery query) {
        //1.分页查询回答数据
        Page<InteractionReply> page = this.lambdaQuery()
                .eq(InteractionReply::getQuestionId, query.getQuestionId())
                .eq(query.getAnswerId() != null, InteractionReply::getAnswerId, query.getAnswerId())
                .page(query.toMpPage("likedTimes", false));
        List<InteractionReply> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            log.info("查询结果为空,暂时还没有人回答");
            return PageDTO.empty(page);
        }
        //2.判断是否匿名
        //2.1
        //3.获取用户信息
        //4.封装数据返回结果
        ArrayList<ReplyVO> list = new ArrayList<>();
        for (InteractionReply record : records) {
            ReplyVO vo = BeanUtil.copyProperties(record, ReplyVO.class);
                UserDTO userDTO = userClient.queryUserById(record.getUserId());
                if (userDTO!=null){
                    vo.setUserName(userDTO.getUsername());//回答者姓名
                    vo.setUserIcon(userDTO.getIcon());//回答者头像
                }

            //5.如果目标评论者不是匿名，设置目标评论者姓名
                    UserDTO userDTO1 = userClient.queryUserById(record.getTargetUserId());
                    if (userDTO!=null){
                        vo.setTargetUserName(userDTO1.getName());//目标评论者姓名
                    }
            list.add(vo);
        }
        return PageDTO.of(page, list);
    }

    @Override
    public void updateBatchById(Long id, Boolean hidden) {
        InteractionReply one = lambdaQuery().eq(InteractionReply::getId, id)
                .one();
        if (one == null){
            throw new RuntimeException("回答不存在");
        }
        // 隐藏当前回答或评论
           lambdaUpdate()
                   .eq(InteractionReply::getId, id)
                   .set(InteractionReply::getHidden, hidden)
                   .update();
        // 如果隐藏的是回答，则隐藏该回答下的所有评论
        if (one.getAnswerId() == null || one.getAnswerId() == 0) {
            List<InteractionReply> list = lambdaQuery()
                    .eq(InteractionReply::getAnswerId, id)
                    .list();
            if (CollUtils.isEmpty(list)){
                return;
            }
            for (InteractionReply reply : list) {
                lambdaUpdate()
                        .eq(InteractionReply::getId, reply.getId())
                        .set(InteractionReply::getHidden, hidden)
                        .update();
            }
        }
    }


    private void handleQuestionStatus(InteractionReply interactionReply,ReplyDTO reply) {
        interactionQuestionMapper.updateQuestionStatus(interactionReply.getQuestionId(),reply.getIsStudent());
    }

    private  void handleAnswer(InteractionReply interactionReply) {
        InteractionQuestion question = interactionQuestionMapper.selectById(interactionReply.getQuestionId());
        if (question == null){
            throw new RuntimeException("问题不存在");
        }
        // 创建更新条件
        interactionQuestionMapper.updateAnswerTimes(interactionReply.getQuestionId());
        //利用mq异步发送添加积分信息到积分表
        SignInMessage message = new SignInMessage();
        message.setUserId(interactionReply.getUserId());
        message.setPoints(5);
        mqHelper.send(MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.WRITE_REPLY,
                message
                );
    }


    private void handleComment(InteractionReply interactionReply) {
        InteractionReply reply = getById(interactionReply.getAnswerId());
        if (reply == null){
            throw new RuntimeException("评论不存在");
        }
        boolean update = this.lambdaUpdate()
                .eq(InteractionReply::getId, interactionReply.getAnswerId())
                .set(InteractionReply::getReplyTimes, reply.getReplyTimes() + 1)
                .update();
        if (!update){
            throw new RuntimeException("更新失败");
        }
        //新增评论
        SignInMessage message = new SignInMessage();
        message.setUserId(interactionReply.getUserId());
        message.setPoints(10);
        mqHelper.send(MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.WRITE_REPLY,
                message
        );
    }

}
